/**
 * 文件名：AbstractProcess.java
 *
 * 创建人：Elvin Zhao - 279152260@qq.com
 *
 * 创建时间：2019年1月2日 下午3:17:12
 *
 * 版权所有：FNII
 */
package com.z100h.supplychain.core.process;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.collections.CollectionUtils;
import org.rribbit.RequestResponseBus;
import org.springframework.beans.factory.annotation.Autowired;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.jeeplus.common.utils.collection.type.Pair;
import com.jeeplus.core.facade.FacadeException;
import com.z100h.supplychain.core.Evidence;
import com.z100h.supplychain.core.EvidenceLockState;
import com.z100h.supplychain.core.EvidenceState;
import com.z100h.supplychain.core.EvidenceType;
import com.z100h.supplychain.core.OuterOrderType;
import com.z100h.supplychain.core.ProductionState;
import com.z100h.supplychain.core.ResourceLockState;
import com.z100h.supplychain.core.ResourceStockoutLockState;
import com.z100h.supplychain.core.StockoutState;
import com.z100h.supplychain.core.biz.entity.CommonEvidence;
import com.z100h.supplychain.evidence.entity.ErpSku;
import com.z100h.supplychain.evidence.entity.StockoutSku;
import com.z100h.supplychain.evidence.service.StockoutErpResourceService;
import com.z100h.supplychain.evidence.service.StockoutService;
import com.z100h.supplychain.evidence.service.StockoutSkuService;
import com.z100h.supplychain.sku.entity.Sku;
import com.z100h.supplychain.sku.service.SkuService;
import com.z100h.supplychain.warehouse.entity.Warehouse.WarehouseType;

/**
 * 
 * 出库单抽象类
 *
 * @author Elvin Zhao - 279152260@qq.com
 * @version 1.0 Created on 2019年1月2日 下午7:24:18
 */
public abstract class AbstractStockoutProcess<T extends Evidence> extends BaseProcess {

	@Autowired
	private StockoutSkuService stockoutSkuService;

	@Autowired
	private SkuService skuService;

	@Autowired
	private StockoutService stockoutService;

	@Autowired
	private StockoutErpResourceService stockoutErpResourceService;

	@Autowired
	private RequestResponseBus rrb;

	/**
	 * 创建 单据
	 * 0.创建 大E表
	 * 1.创建 out_detail
	 * 2.创建 out_sku
	 * 3.创建out_res 售卖
	 * 
	 * @param evidence
	 * @param skus
	 * @param evidenceState
	 * @return
	 * @author: Elvin Zhao - 279152260@qq.com 
	 * @date: Created on 2019年1月18日 下午2:58:57
	 */
	@Deprecated
	protected abstract String createEvidence(T evidence, List<Pair<Sku, Integer>> skus, EvidenceState evidenceState,
			JSONArray skuList, List<String> orderId, String stockroomId);

	protected abstract List<String> createEvidence(T evidence, EvidenceState evidenceState, JSONArray skuList,
			String stockroomId);

	/**
	 * 更具单据修改资源
	 * 
	 * @param evidenceId
	 * @param resourceIds
	 * @author: Elvin Zhao - 279152260@qq.com 
	 * @date: Created on 2019年1月2日 下午4:59:52
	 */
	protected abstract void changeResourceWithEvidence(final T evidence, final List<String> resourceIds);

	/**
	 * 
	 * 快速出库流程
	 * @param stockoutSku
	 * @param fromEvidenceLockState 条件抓取目标可用资源
	 * @param toResourceStockoutLockState
	 * @author: Elvin Zhao - 279152260@qq.com 
	 * @date: Created on 2019年5月14日 下午4:56:43
	 */
	protected abstract void quicklyComfirmResource(final StockoutSku stockoutSku, final String companyId,
			final ResourceStockoutLockState toResourceStockoutLockState);

	protected abstract void quicklyComfirmResourceToErpSku(final ErpSku erpSku, final String companyId,
			final ResourceStockoutLockState toResourceStockoutLockState);

	/**
	 * 检查过机确认资源 是否超过单子的sku数量
	 * 返回超量的sku及数量
	 * @param evidence
	 * @param resourceIds
	 * @author: Elvin Zhao - 279152260@qq.com 
	 * @date: Created on 2019年1月17日 上午10:08:13
	 */
	protected abstract List<Pair<Sku, Integer>> checkConfirmResource(final String evidenceId,
			final List<String> resourceIds);

	/**
	 * 资源加[出库锁]
	 * 
	 * @param resourceIds
	 * @param resourceStockoutLockState
	 * @return
	 * @author: Elvin Zhao - 279152260@qq.com 
	 * @date: Created on 2019年1月17日 下午4:59:25
	 */
	protected abstract Boolean stockoutLockResource(final List<String> resourceIds,
			ResourceStockoutLockState resourceStockoutLockState);

	/**
	 * 出库单完成状态检查，比较已经出库的资源和 需要出库的sku及num
	 * 
	 * @param evidenceId
	 * @return
	 * @author: Elvin Zhao - 279152260@qq.com 
	 * @date: Created on 2019年1月17日 下午4:59:53
	 */
	protected abstract List<Pair<Sku, Integer>> checkEvidenceFinish(final String evidenceId);

	/**
	 * 保存到 sc_e_出库单_res表明细
	 * 刷新sc_e_amountOut
	 * 
	 * @param resourceIds
	 * @param evidenceId
	 * @author: Elvin Zhao - 279152260@qq.com 
	 * @date: Created on 2019年1月17日 下午5:02:12
	 */
	protected abstract void saveConfirmedResource(final List<String> resourceIds, final String evidenceId);

	/**
	 * 跨系统订单分解
	 * @param orderId
	 * @param orderType
	 * @return
	 * @author: Elvin Zhao - 279152260@qq.com 
	 * @date: Created on 2019年1月18日 下午2:59:29
	 */
	protected abstract List<Pair<Sku, Integer>> od(final String orderId, final OuterOrderType orderType);

	/**
	 * 检查实时库存
	 * 实时库存-skus-moreAmount = ？
	 * 
	 * @param skus
	 * @param moreAmount	阈值
	 * @return
	 * @author: Elvin Zhao - 279152260@qq.com 
	 * @date: Created on 2019年1月18日 下午3:00:09
	 */
	protected abstract List<Pair<Sku, Integer>> ckeckRealtimeInventory(final List<Pair<Sku, Integer>> skus,
			final Integer moreAmount);

	/**
	 * 出库确认是检查实时库存 bySKU
	 * 功能实现描述
	 * 
	 * @param stockoutSku
	 * @return
	 * @author: Elvin Zhao - 279152260@qq.com 
	 * @date: Created on 2019年5月14日 下午4:03:27
	 */
	protected abstract boolean ckeckRealtimeInventoryBySku(final StockoutSku stockoutSku, final String companyId);

	/**
	 * 出库确认是检查实时库存 bySKU
	 * 功能实现描述
	 * 
	 * @param ErpSku
	 * @param companyId
	 * @return
	 * @author: Elvin Zhao - 279152260@qq.com 
	 * @date: Created on 2019年9月11日 上午11:16:13
	 */
	protected abstract boolean ckeckRealtimeInventoryByErpSku(final ErpSku ErpSku, final String companyId);

	/**
	 * 外部系统调用的出库单调用方法
	 * 
	 * @param orderId
	 * @param orderType
	 * @param evidence
	 * @return
	 * @author: Elvin Zhao - 279152260@qq.com 
	 * @date: Created on 2019年1月18日 下午2:45:00
	 */
	public List<String> createProcess(String orderId, OuterOrderType orderType, T evidence, List<String> orderIds,
			String stockroomId) {
		return createProcess(orderId, orderType, evidence, null, orderIds, stockroomId);
	}

	/**
	 * 手工建立的出库单 调用方法
	 * 
	 * @param skus
	 * @param evidence
	 * @return
	 * @author: Elvin Zhao - 279152260@qq.com 
	 * @date: Created on 2019年1月18日 下午2:47:06
	 */
	public List<String> createProcess(T evidence, JSONArray skuList, List<String> orderIds, String stockroomId) {
		return createProcess(null, null, evidence, skuList, orderIds, stockroomId);
	}

	/**
	 * 
	 * 私有方法，外部方法见重载方法
	 * 0.见方法体内	
	 * 
	 * @param skus			已经分解的SKU-NUM关系
	 * @param orderId		外部订单Id
	 * @param orderType		外部订单类型
	 * @param evidence		凭据
	 * @return
	 * @throws FacadeException
	 * @author: Elvin Zhao - 279152260@qq.com 
	 * @date: Created on 2019年1月19日 上午10:27:47
	 */
	private List<String> createProcess(String orderId, OuterOrderType orderType, T evidence, JSONArray skuList,
			List<String> orderIds, String stockroomId) throws FacadeException {
		// List<Pair<Sku, Integer>> skus = null;
		// if (CollectionUtils.isNotEmpty(skuList)) {
		// skus = this.getPariList(skuList);
		// }
		//
		// /**
		// * 判定是外部出库单还是手工出库单
		// * 外部出库单需要先做订单分解
		// */
		// if (orderId != null && orderType != null) {
		// /**
		// * 订单分解sku
		// * TODO 需要ERP系统配合
		// */
		// skus = od(orderId, orderType);
		// }
		/**
		 * 判定订单分解是否成功
		 */
		// if (CollectionUtils.isNotEmpty(skus)) {
		/**
		 * 检查实时库存 XXX 需要高性能
		 * 0为保留库存
		 */
		// ckeckRealtimeInventory(skus, 0);

		/**
		 * 判定库存检查是否存在异常
		 */
		// if (CollectionUtils.isEmpty(errorList)) {

		/**
		 * 0.创建 大E表
		 * 1.创建 out_detail
		 * 2.创建 out_sku
		 */
		// return createEvidence(evidence, skus, EvidenceState.CREATE, skuList, orderIds, stockroomId);

		return createEvidence(evidence, EvidenceState.CREATE, skuList, stockroomId);
		// } else {
		// throw new FacadeException("失败：库存异常！");// TODO 无法显示异常内容
		// }

		// } else {
		// throw new FacadeException("失败：订单分解异常！");
		// }

	}

	/**
	 * 
	 * 0.见方法体内
	 * 
	 * @param resourceIds
	 * @param evidence
	 * @return
	 * @throws FacadeException
	 * @author: Elvin Zhao - 279152260@qq.com 
	 * @date: Created on 2019年1月17日 下午3:52:03
	 */
	public List<Pair<Sku, Integer>> confirmProcess(final List<String> resourceIds, final T evidence)
			throws FacadeException {

		if (CollectionUtils.isNotEmpty(resourceIds)) {

			/**
			 * 检查资源 [凭据锁]解锁状态 [出库锁]解锁状态 [仓库类型]商品库
			 * 返回异常数据
			 */
			List<String> lockedResourceIds = checkResource(resourceIds, EvidenceLockState.UNLOCK,
					ResourceStockoutLockState.UNLOCK, WarehouseType.PRODUCT);

			/**
			 * 判定资源异常锁定状态的
			 */
			if (CollectionUtils.isEmpty(lockedResourceIds)) {

				/**
				 * 根据上报的 资源id 找到资源id的sku 在 出库单对应sku表 + 出库单对应资源表 判定数量有没有超出，超出的列出sku超出量
				 */
				List<Pair<Sku, Integer>> errorList = checkConfirmResource(evidence.getEvidenceId(), resourceIds);

				/**
				 * 没有异常超出的数据，继续流程
				 */
				if (CollectionUtils.isEmpty(errorList)) {

					/**
					 * 凭据锁 锁定资源
					 */
					Boolean resourceLockState = lockResource(resourceIds, EvidenceLockState.LOCK);

					/**
					 * 判定资源[凭据锁]是否成功
					 */
					if (resourceLockState) {

						/**
						 * 刷资源的凭据id为出库单id
						 */
						associateEvidenceWithResource(evidence.getEvidenceId(), resourceIds);

						/**
						 * 刷资源的仓库为对应仓库
						 */
						changeResourceWithEvidence(evidence, resourceIds);
						/**
						 * 资源加[出库锁]锁定状态
						 * 此处是否要分[出库锁]的类型 ResourceStockoutLockState
						 * 
						 */
						Boolean resourceStockoutLockState = stockoutLockResource(resourceIds,
								ResourceStockoutLockState.LOCK);

						/**
						 * 判定资源[出库锁]是否成功
						 */
						if (resourceStockoutLockState) {
							/**
							 * 资源[凭据锁]解锁
							 */
							Boolean resourceUnlockState = unlockResource(resourceIds, EvidenceLockState.UNLOCK);
							/**
							 * 判定资源[凭据锁]解锁是否成功
							 */
							if (resourceUnlockState) {

								/**
								 * 已经确认的转存
								 */
								saveConfirmedResource(resourceIds, evidence.getEvidenceId());
								/**
								 * 记录资源日志
								 */
								resourceLogging(evidence.getEvidenceId(), ResourceLockState.UNLOCK, resourceIds);
							} else {
								throw new FacadeException("失败：资源解锁异常！");
							}
						} else {
							throw new FacadeException("失败：资源出库锁定异常！");
						}
					} else {
						throw new FacadeException("失败：资源锁定异常！");
					}
				}
				return errorList;

			} else {
				throw new FacadeException("失败：资源存在锁定状态！");
			}
		} else {
			throw new FacadeException("失败：资源为空！");
		}

	}

	/**
	 * 完成 及 检查
	 * 
	 * @param evidenceId
	 * @return
	 * @throws FacadeException
	 * @author: Elvin Zhao - 279152260@qq.com 
	 * @date: Created on 2019年1月17日 下午4:56:04
	 */
	public List<Pair<Sku, Integer>> finishProcess(final String evidenceId) throws FacadeException {
		/**
		 * 获取单子未结束SKU及数量
		 */
		List<Pair<Sku, Integer>> unfinishList = checkEvidenceFinish(evidenceId);

		if (CollectionUtils.isEmpty(unfinishList)) {
			finishEvidence(evidenceId, EvidenceState.FINISH);
		}
		return unfinishList;
	}

	/**
	 * 转换方法
	 * 
	 * @param skuList
	 * @return
	 * @author: Elvin Zhao - 279152260@qq.com 
	 * @date: Created on 2019年4月10日 下午2:55:08
	 */
	@SuppressWarnings("unused")
	private List<Pair<Sku, Integer>> getPariList(JSONArray skuList) {
		List<Pair<Sku, Integer>> pairList = new ArrayList<>();
		JSONObject objectItem;

		for (int i = 0; i < skuList.size(); i++) {
			objectItem = (JSONObject) skuList.get(i);
			Pair<Sku, Integer> pair = new Pair<Sku, Integer>(skuService.get(objectItem.getString("skuId")),
					objectItem.getInteger("num"));
			pairList.add(pair);
		}
		return pairList;
	}

	/**
	 * 
	 * 未完成的出库单自动出库
	 * 
	 * @author: Fyh - 1009173473@qq.com 
	 * @date: Created on 2019年5月15日 上午9:23:14
	 */
	public void confirmFinishProcess() throws FacadeException {

		try {
			// 获取未完成出库单TODO 如果可以 orderBy companyId
			List<CommonEvidence> unfinishStockoutEvidenceList = commonEvidenceService
					.findUnfinishStockoutEvidenceList();
			// 记录不足的SKU
			Set<String> unavailableSkus = new HashSet<String>();
			if (CollectionUtils.isNotEmpty(unfinishStockoutEvidenceList)) {
				for (CommonEvidence evidence : unfinishStockoutEvidenceList) {

					// TODO 获取未出库sku，此处注意条件amount is null 方法需要重写
					List<StockoutSku> stockoutSkuList = stockoutSkuService
							.findUnStockoutSkuListByEvidenceId(evidence.getId());

					if (CollectionUtils.isNotEmpty(stockoutSkuList)) {
						for (StockoutSku stockoutSku : stockoutSkuList) {

							// TODO 检查单个SKU库存是否可用 此处需要关联大E表的companyId
							boolean isAvailable = ckeckRealtimeInventoryBySku(stockoutSku, evidence.getCompanyId());
							if (isAvailable) {

								/**
								 * TODO 
								 * 1.顺序出库 orderBy resid limit sku.amount
								 * 2.刷 skudetail表的 amount_out列
								 */
								quicklyComfirmResource(stockoutSku, evidence.getCompanyId(),
										ResourceStockoutLockState.LOCK);

								// TODO 通过 单子id skuid去logging
								resourceLogging(stockoutSku, ResourceLockState.UNLOCK);
							} else {
								// 库存不可用的记录，发通知用
								unavailableSkus.add(stockoutSku.getSkuId().toString());
							}
						}
					}
					// 检查是否完成，完成刷单子状态
					List<Pair<Sku, Integer>> unfinishList = checkEvidenceFinish(evidence.getId());
					if (CollectionUtils.isEmpty(unfinishList)) {
						finishEvidence(evidence.getId(), EvidenceState.FINISH);
					}
				}
			}
		} catch (Exception e) {
			throw new FacadeException("失败：SKU资源确认出库异常！");
		}

	}

	/**
	 * 质检并出SKU库存
	 * 
	 * @param erpResIds
	 * @param evidenceId
	 * @author: Elvin Zhao - 279152260@qq.com 
	 * @throws Throwable 
	 * @date: Created on 2019年9月16日 上午9:19:09
	 */
	protected void qcConfirmFinishProcess(List<String> erpResIds, String evidenceId) throws Throwable {
		try {

			List<String> orderServiceIds = stockoutService.findStockoutOrderByEid(evidenceId);
			List<String> repairServiceIds = stockoutService.findStockoutRepairByEid(evidenceId);

			if (CollectionUtils.isNotEmpty(erpResIds)) {
				// 记录不足的SKU
				Set<String> unavailableSkus = new HashSet<String>();

				CommonEvidence evidence = commonEvidenceService.get(evidenceId);

				if (CollectionUtils.isNotEmpty(erpResIds)) {

					for (String resId : erpResIds) {

						// 获取每个资源id对应的 sku
						List<ErpSku> erpResSkuList = stockoutErpResourceService.findUnStockoutSkuListByErpResId(
								evidenceId, resId, orderServiceIds, repairServiceIds, evidence.getEvidenceType());

						if (CollectionUtils.isNotEmpty(erpResSkuList)) {

							for (ErpSku sku : erpResSkuList) {// TODO 应该优化成 一个 erpid一次整体出库
								// 检查单个SKU库存是否可用 此处需要关联大E表的companyId
								boolean isAvailable = ckeckRealtimeInventoryByErpSku(sku, evidence.getCompanyId());
								if (isAvailable) {
									/**
									 * 1.顺序出库 orderBy resid limit sku.amount
									 * 2.刷 skudetail表的 amount_out列
									 */
									quicklyComfirmResourceToErpSku(sku, evidence.getCompanyId(),
											ResourceStockoutLockState.LOCK);

								} else {
									// 库存不可用的记录，发通知用
									unavailableSkus.add(resId);
									throw new FacadeException(
											"失败：质检出库异常！ERP资源SKU不足，SKUID:" + sku.getSkuId() + "，资源ID:" + resId);
								}
							}
						} else {
							throw new FacadeException("失败：质检出库异常！资源无法关联SKU，资源ID:" + resId);
						}
						// 通过 erp_res_id && sku_id去logging
						resourceLogging(resId, evidenceId, ResourceLockState.UNLOCK);
					}
					// 出库类型
					String stockoutType = commonEvidenceService.findType(evidenceId);
					if (EvidenceType.REPAIROUT.getType().equals(stockoutType)) {
						List<String> repairIds = stockoutErpResourceService.findServiceId(evidenceId, erpResIds);
						if (CollectionUtils.isNotEmpty(repairIds)) {
							stockoutService.finishRepair(repairIds);
						}
					}
				} else {
					throw new FacadeException("失败：质检出库异常！单据无法关联ERP资源，单据ID:" + evidenceId);
				}
				stockoutErpResourceService.updateResQcStateByErpResIds(evidenceId, erpResIds,
						ProductionState.QCPASS.getType());
			} else {
				throw new FacadeException("失败：质检出库异常！单据无法关联ERP业务，单据ID:" + evidenceId);
			}
		} catch (Exception e) {
			throw new FacadeException(e.getMessage());
		}
	}

	/**
	 * 
	 * 质检并出SKU库存
	 * 
	 * @param evidenceId
	 * @date: Created on 2019年9月16日 下午2:00:41
	 * @author: Elvin Zhao - 279152260@qq.com 
	 * @throws Throwable 
	 */
	protected void qcConfirmFinishProcess(String evidenceId) throws Throwable {
		try {

			/**
			 * 订单业务ID
			 * 订单资源ID
			 */
			List<String> orderServiceIds = stockoutService.findStockoutOrderByEid(evidenceId);
			List<String> orderResIds = stockoutErpResourceService
					.findProductionCompletionErpOrderResIdByEid(evidenceId);

			/**
			 * 复壮业务ID
			 * 复壮资源ID
			 */
			List<String> repairServiceIds = stockoutService.findStockoutRepairByEid(evidenceId);

			List<String> repairResIds = stockoutErpResourceService
					.findProductionCompletionErpRepairResIdByEid(evidenceId);

			/**
			 * 业务双空检查
			 */
			if (CollectionUtils.isEmpty(orderServiceIds) && CollectionUtils.isEmpty(repairServiceIds)) {
				throw new FacadeException("失败：质检出库异常！关联检查后发现，单据无法关联ERP业务ID，SC单据ID:" + evidenceId);
			}

			/**
			 * 资源双空检查
			 */
			if (CollectionUtils.isEmpty(orderResIds) && CollectionUtils.isEmpty(repairResIds)) {
				throw new FacadeException("失败：质检出库异常！关联检查后发现，订单的单据无法关联ERP资源ID，SC单据ID:" + evidenceId);
			}

			CommonEvidence evidence = commonEvidenceService.get(evidenceId);

			/**
			 ********************************************
			 * 订单
			 ********************************************
			 */

			if (CollectionUtils.isNotEmpty(orderResIds) && CollectionUtils.isNotEmpty(orderServiceIds)) {

				for (String resId : orderResIds) {

					// 获取每个资源id对应的 sku
					List<ErpSku> erpResSkuList = stockoutErpResourceService.findUnStockoutSkuListByErpOrderResId(
							evidenceId, resId, orderServiceIds, evidence.getEvidenceType());

					if (CollectionUtils.isNotEmpty(erpResSkuList)) {

						for (ErpSku sku : erpResSkuList) {

							// 检查单个SKU库存是否可用 此处需要关联大E表的companyId
							boolean isAvailable = ckeckRealtimeInventoryByErpSku(sku, evidence.getCompanyId());
							if (isAvailable) {
								/**
								 * 1.顺序出库 orderBy resid limit sku.amount
								 * 2.刷 skudetail表的 amount_out列
								 */
								quicklyComfirmResourceToErpSku(sku, evidence.getCompanyId(),
										ResourceStockoutLockState.LOCK);
							} else {
								// 库存不可用的记录，发通知用
								throw new FacadeException("失败：质检出库异常！订单的ERP资源SKU不足，SKUID:" + sku.getSkuId() + "，资源ID:"
										+ resId + "，SC单据ID:" + evidenceId);
							}
						}
					}
					// else {
					// throw new FacadeException("失败：质检出库异常！订单的资源无法关联SKU，资源ID:" + resId + "，SC单据ID:" + evidenceId);
					// }

					// 通过 erp_res_id && sku_id去logging
					resourceLogging(resId, evidenceId, ResourceLockState.UNLOCK);
				}

			}

			/**
			 ********************************************
			 * 复壮
			 ********************************************
			 */
			if (CollectionUtils.isNotEmpty(repairResIds) && CollectionUtils.isNotEmpty(repairServiceIds)) {

				for (String resId : repairResIds) {

					// 获取每个资源id对应的 sku
					List<ErpSku> erpResSkuList = stockoutErpResourceService.findUnStockoutSkuListByErpRepairResId(
							evidenceId, resId, repairServiceIds, evidence.getEvidenceType());
					if (CollectionUtils.isNotEmpty(erpResSkuList)) {

						for (ErpSku sku : erpResSkuList) {

							// 检查单个SKU库存是否可用 此处需要关联大E表的companyId
							boolean isAvailable = ckeckRealtimeInventoryByErpSku(sku, evidence.getCompanyId());
							if (isAvailable) {
								/**
								 * 1.顺序出库 orderBy resid limit sku.amount
								 * 2.刷 skudetail表的 amount_out列
								 */
								quicklyComfirmResourceToErpSku(sku, evidence.getCompanyId(),
										ResourceStockoutLockState.LOCK);

							} else {
								// 库存不可用的记录，发通知用
								throw new FacadeException("失败：质检出库异常！复壮ERP资源SKU不足，SKUID:" + sku.getSkuId() + "，资源ID:"
										+ resId + "，SC单据ID:" + evidenceId);
							}
						}
					}
					// else {
					// throw new FacadeException("失败：质检出库异常！复壮资源无法关联SKU，资源ID:" + resId + "，SC单据ID:" + evidenceId);
					// }

					// 通过 erp_res_id && sku_id去logging
					resourceLogging(resId, evidenceId, ResourceLockState.UNLOCK);
				}

			}

			List<String> unfinishSkuList = stockoutSkuService.findUnfinishSkuByEid(evidenceId);
			if (CollectionUtils.isNotEmpty(unfinishSkuList)) {
				throw new FacadeException(
						"失败：质检出库异常！订单、复壮质检流程结束，但SKU未出完！SKUID:" + unfinishSkuList + "，SC单据ID:" + evidenceId);
			}

			if (CollectionUtils.isNotEmpty(repairResIds) && CollectionUtils.isNotEmpty(repairServiceIds)) {
				// /**
				// * 加急单质检无需完成复壮
				// */
				// Stockout stockout = stockoutService.get(evidenceId);
				// if (stockout != null && !StringUtils.equals("0", stockout.getIsUrgent())) {
				// stockoutService.finishRepair(repairServiceIds);
				// }
			}

			stockoutErpResourceService.updateResQcState(evidenceId, ProductionState.QCPASS.getType());
			stockoutService.updateStockoutState(evidenceId, StockoutState.WAITINGFORSTOCKOUT);
			/**
			 * 订单走流程
			 */
			// stockoutService.claim(evidenceId);

		} catch (Exception e) {
			throw new FacadeException(e.getMessage());
		}

	}

	/**
	 * 
	 * 标准出库单出库
	 * 
	 * @param evidenceId
	 * @throws FacadeException
	 * @author: Fyh - 1009173473@qq.com 
	 * @date: Created on 2019年10月16日 下午6:21:44
	 */
	public void outCommonStockoutProcess(String evidenceId) throws FacadeException {
		try {
			List<StockoutSku> stockoutSkuList = stockoutSkuService.findUnStockoutSkuListByEvidenceId(evidenceId);
			CommonEvidence commonEvidence = commonEvidenceService.get(evidenceId);
			if (CollectionUtils.isNotEmpty(stockoutSkuList)) {
				for (StockoutSku stockoutSku : stockoutSkuList) {
					// TODO 检查单个SKU库存是否可用 此处需要关联大E表的companyId
					boolean isAvailable = ckeckRealtimeInventoryBySku(stockoutSku, commonEvidence.getCompanyId());
					if (isAvailable) {

						/**
						 * TODO 
						 * 1.顺序出库 orderBy resid limit sku.amount
						 * 2.刷 skudetail表的 amount_out列
						 */
						quicklyComfirmResource(stockoutSku, commonEvidence.getCompanyId(),
								ResourceStockoutLockState.LOCK);

						// TODO 通过 单子id skuid去logging
						resourceLogging(stockoutSku, ResourceLockState.UNLOCK);
					} else {
						throw new FacadeException("SKU不足，不允许完成！");
					}
				}
			}
			// 检查是否完成，完成刷单子状态
			List<Pair<Sku, Integer>> unfinishList = checkEvidenceFinish(evidenceId);
			if (CollectionUtils.isEmpty(unfinishList)) {
				finishEvidence(evidenceId, EvidenceState.FINISH);
			}
			// stockout表刷完成
			stockoutService.updateStockoutState(evidenceId, StockoutState.FINISH);

		} catch (Exception e) {
			throw new FacadeException("失败：SKU资源确认出库异常！");
		}

	}

}
